﻿using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Web; 
using System.Web.Mvc;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
using System;

namespace SRF.UI.Html
{
    public static class EnumExtensions
    {
        #region EnumDropDownList Value

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Enum value)
        {
            return EnumDropDownList(htmlHelper, name, value, null /* optionLabel */, null /* htmlAttributes */);
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Enum value, object htmlAttributes)
        {
            return EnumDropDownList(htmlHelper, name, value, null /* optionLabel */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Enum value, IDictionary<string, object> htmlAttributes)
        {
            return EnumDropDownList(htmlHelper, name, value, null /* optionLabel */, htmlAttributes);
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Enum value, string optionLabel)
        {
            return EnumDropDownList(htmlHelper, name, value, optionLabel, null /* htmlAttributes */);
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Enum value, string optionLabel, object htmlAttributes)
        {
            return EnumDropDownList(htmlHelper, name, value, optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Enum value, string optionLabel, IDictionary<string, object> htmlAttributes)
        {
            return System.Web.Mvc.Html.SelectExtensions.DropDownList(htmlHelper, name, GetSelectList(value), optionLabel, htmlAttributes);
        }

        #endregion

        #region EnumDropDownList Type

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Type type)
        {
            return EnumDropDownList(htmlHelper, name, type, null /* optionLabel */, null /* htmlAttributes */);
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Type type, object htmlAttributes)
        {
            return EnumDropDownList(htmlHelper, name, type, null /* optionLabel */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Type type, IDictionary<string, object> htmlAttributes)
        {
            return EnumDropDownList(htmlHelper, name, type, null /* optionLabel */, htmlAttributes);
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Type type, string optionLabel)
        {
            return EnumDropDownList(htmlHelper, name, type, optionLabel, null /* htmlAttributes */);
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Type type, string optionLabel, object htmlAttributes)
        {
            return EnumDropDownList(htmlHelper, name, type, optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper, string name, System.Type type, string optionLabel, IDictionary<string, object> htmlAttributes)
        {
            return System.Web.Mvc.Html.SelectExtensions.DropDownList(htmlHelper, name, GetSelectList(type), optionLabel, htmlAttributes);
        }

        #endregion

        #region  EnumDropDownListFor

        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
        public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string[] excludes = null)
        {
            return EnumDropDownListFor(htmlHelper, expression, null /* optionLabel */, null /* htmlAttributes */, excludes);
        }

        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
        public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes, string[] excludes = null)
        {
            return EnumDropDownListFor(htmlHelper, expression, null /* optionLabel */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes), excludes);
        }

        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
        public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes, string[] excludes = null)
        {
            return EnumDropDownListFor(htmlHelper, expression, null /* optionLabel */, htmlAttributes, excludes);
        }

        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
        public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string optionLabel, string[] excludes = null)
        {
            return EnumDropDownListFor(htmlHelper, expression, optionLabel, null /* htmlAttributes */, excludes);
        }

        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
        public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string optionLabel, object htmlAttributes, string[] excludes = null)
        {
            return System.Web.Mvc.Html.SelectExtensions.DropDownListFor(htmlHelper, expression, GetSelectList(expression.ReturnType, excludes), optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        #endregion

        private static IEnumerable<SelectListItem> GetSelectList(System.Enum value, string[] excludes = null)
        {
            IList<SelectListItem> items = new List<SelectListItem>();
            foreach (FieldInfo field in value.GetType().GetFields(BindingFlags.Public | BindingFlags.Static))
            {
                string text = "";
                var attrs = field.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
                if (attrs != null && attrs.Length > 0)
                {
                    text = ((System.ComponentModel.DescriptionAttribute)attrs[0]).Description;
                }
                else
                {
                    text = field.Name;
                }
                if (excludes == null || !excludes.Contains(field.Name))
                {
                    items.Add(new SelectListItem()
                    {
                        Text = text,
                        Value = field.Name,
                        Selected = System.Enum.GetName(value.GetType(), value) == field.Name
                    });
                }
            }

            return items;
        }
        private static IEnumerable<SelectListItem> GetSelectList(Type type, string[] excludes = null)
        {
            IList<SelectListItem> items = new List<SelectListItem>();
            foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.Static))
            {
                string text = "";
                var attrs = field.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
                if (attrs != null && attrs.Length > 0)
                {
                    text = ((System.ComponentModel.DescriptionAttribute)attrs[0]).Description;
                }
                else
                {
                    text = field.Name;
                }
                if (excludes == null || !excludes.Contains(field.Name))
                {
                    items.Add(new SelectListItem()
                    {
                        Text = text,
                        Value = field.Name,
                    });
                }
            }

            return items;
        }

        #region EnumText

        public static MvcHtmlString EnumText(this HtmlHelper htmlHelper, System.Enum value)
        {
            string text = "";
            FieldInfo field = value.GetType().GetFields(BindingFlags.Public | BindingFlags.Static).First(fi => fi.Name == value.ToString());
            var attrs = field.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
            if (attrs != null && attrs.Length > 0)
            {
                text = ((System.ComponentModel.DescriptionAttribute)attrs[0]).Description;
            }
            return new MvcHtmlString(text);
        }

        public static MvcHtmlString EnumText(this HtmlHelper htmlHelper, Type type, object value)
        {
            string text = "";
            FieldInfo field = type.GetFields(BindingFlags.Public | BindingFlags.Static).Single(fi => fi.Name == value.ToString());
            var attrs = field.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
            if (attrs != null && attrs.Length > 0)
            {
                text = ((System.ComponentModel.DescriptionAttribute)attrs[0]).Description;
            }
            return new MvcHtmlString(text);
        }

        #endregion

        #region EnumTextFor

        public static MvcHtmlString EnumTextFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
        {
            string text = "";
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            FieldInfo field = expression.ReturnType.GetFields(BindingFlags.Public | BindingFlags.Static).First(fi => fi.Name == metadata.Model.ToString());
            var attrs = field.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
            if (attrs != null && attrs.Length > 0)
            {
                text = ((System.ComponentModel.DescriptionAttribute)attrs[0]).Description;
            }

            return new MvcHtmlString(text);
        }

        #endregion
    }
}